#include "stdafx.h"
#include "TimeVal.h"
#include "TypeDefination.h"

namespace serika
{
	namespace ut
	{
		const long ONE_SEC_IN_USEC = 1000000L;
	
		TimeVal::TimeVal()
		{
			tv_sec = tv_usec = 0;
		}
	
		TimeVal::TimeVal(const TimeVal& other)
		{
			tv_sec = other.tv_sec;
			tv_usec = other.tv_usec;
		}
	
		const TimeVal& TimeVal::Now()
		{
			static TimeVal tv;
	#ifdef WIN32
			FILETIME ftime;
			GetSystemTimeAsFileTime(&ftime);
			const INT64 skew = 0x19db1ded53e8000i64;
			ULARGE_INTEGER _100ns;
			_100ns.LowPart = ftime.dwLowDateTime;
			_100ns.HighPart = ftime.dwHighDateTime;
			_100ns.QuadPart -= skew;
	
			// Convert 100ns units to seconds;
			tv.tv_sec = (long) (_100ns.QuadPart / (10 * 1000 * 1000));
			// Convert remainder to nanoseconds;
			tv.tv_usec = (long) ((_100ns.QuadPart % (10 * 1000 * 1000)) / 10);
	
			tv.Normalize();
	#else
			gettimeofday(&tv, 0);
	#endif
			return tv;
		}
	
		double TimeVal::ToSeconds() const
		{
			return tv_sec + (double)tv_usec / ONE_SEC_IN_USEC;
		}
	
		void TimeVal::Reload()
		{
			(*this) = TimeVal::Now();
		}
	
		bool TimeVal::operator < (const TimeVal& other) const
		{
			if (tv_sec < other.tv_sec)
			{
				return true;
			}
			else if (tv_sec == other.tv_sec)
			{
				return tv_usec < other.tv_usec;
			}
			else
			{
				return false;
			}
		}
	
		bool TimeVal::operator == (const TimeVal& other) const
		{
			return tv_sec == other.tv_sec && tv_usec == other.tv_usec;
		}
	
		bool TimeVal::operator != (const TimeVal& other) const
		{
			return !(*this == other);
		}
	
		bool TimeVal::operator > (const TimeVal& other) const
		{
			return !(*this < other || *this == other);
		}
	
		bool TimeVal::operator <= (const TimeVal& other) const
		{
			return *this < other || *this == other;
		}
	
		bool TimeVal::operator >= (const TimeVal& other) const
		{
			return *this > other || *this == other;
		}
	
		TimeVal& TimeVal::operator = (const TimeVal& other)
		{
			if (&other == this)
			{
				return *this;
			}
			tv_sec = other.tv_sec;
			tv_usec = other.tv_usec;
			return *this;
		}
	
		TimeVal TimeVal::operator - (const TimeVal& other) const
		{
			TimeVal ret;
			ret.tv_sec = tv_sec - other.tv_sec;
			ret.tv_usec = tv_usec - other.tv_usec;
			ret.Normalize();
			return ret;
		}
	
		TimeVal TimeVal::operator + (const TimeVal& other) const
		{
			TimeVal ret;
			ret.tv_sec = tv_sec + other.tv_sec;
			ret.tv_usec = tv_usec + other.tv_usec;
			ret.Normalize();
			return ret;
		}
	
		TimeVal& TimeVal::operator -= (const TimeVal& other)
		{
			tv_sec -= other.tv_sec;
			tv_usec -= other.tv_usec;
			this->Normalize();
			return *this;
		}
	
		TimeVal& TimeVal::operator += (const TimeVal& other)
		{
			tv_sec += other.tv_sec;
			tv_usec += other.tv_usec;
			this->Normalize();
			return *this;
		}
	
		inline void TimeVal::Normalize()
		{
			if (tv_usec >= ONE_SEC_IN_USEC)
			{
				do
				{
					++tv_sec;
					tv_usec -= ONE_SEC_IN_USEC;
				}
				while (tv_usec >= ONE_SEC_IN_USEC);
			}
			else if (tv_usec <= -ONE_SEC_IN_USEC)
			{
				do
				{
					--tv_sec;
					tv_usec += ONE_SEC_IN_USEC;
				}
				while (tv_usec <= -ONE_SEC_IN_USEC);
			}
	
			if (tv_sec >= 1 && tv_usec < 0)
			{
				--tv_sec;
				tv_usec += ONE_SEC_IN_USEC;
			}
		}
	}
}
